using System;
using System.Web;
using System.Web.UI.HtmlControls;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Security.Permissions;
using System.Web.UI.Design;
using System.Text;
using System.Collections.Generic;

using Heckel.EasyTools.Diagramming.Drawing;

namespace Heckel.EasyTools.Diagramming
{
    public enum CallBackType
    {
        NodeBeingRepositioned = 0,
        NodeDoubleClicked = 1,
        CheckingNodeStatuses = 2,
        NodeDetailsClicked = 3,
        NodeDeleted = 4,
        Undefined = 6,
        DiagramInitialized = 7
    }

    public enum LineType
    {
        [StringValue("undefined")]
        Undefined = -1,
        [StringValue("direct")]
        Direct = 0,
        [StringValue("right")]
        RightAngle = 1
    }

    public enum LineDecoration
    {
        Undefined = -1,
        Solid = 0,
        Dotted = 1
    }

    public enum ExecutingEvent
    {
        [StringValue("StatusElapsed")]
        StatusElapsed = 0,
        [StringValue("DoubleClicked")]
        DoubleClicked = 1,
        [StringValue("Repositioned")]
        Repositioned = 2,
        [StringValue("DetailsClicked")]
        DetailsClicked = 3,
        [StringValue("DeleteClicked")]
        DeleteClicked = 4,
        [StringValue("DiagramInitialized")]
        DiagramInitialized = 5
    }

    public delegate void NodeCheckStatusEventHandler(object o, NodeStatusEventArgs e);
    public delegate void NodeRepositionedEventHandler(object o, NodeRepositionEventArgs e);
    public delegate void NodeDoubleClickedEventHandler(object o, NodeDetailsEventArgs e);
    public delegate void NodeDetailsClickedEventHandler(object o, NodeDetailsEventArgs e);
    public delegate void NodeDeleteClickedEventHandler(object o, NodeDetailsEventArgs e);
    public delegate void DiagramInitializedEventHandler(object o, DiagramInitializedEventArgs e);

    [
    ToolboxData("<{0}:DiagramContainer runat=server></{0}:DiagramContainer>"),
    Designer(typeof(Heckel.EasyTools.Diagramming.DiagramDesigner))
    ]
    public class DiagramContainer : CompositeControl, ICallbackEventHandler, INamingContainer
    {
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Br;
            }
        }

        internal bool IsEnclosedInUpdatePanel
        {
            get
            {
                bool getVal = this.Parent.Parent.GetType() == typeof(UpdatePanel);
                return getVal;
            }
        }

        private NodeStatusEventArgs checkNodeStatus;

        [Category("Action"), Description("Raised when the status timer associated with NodeStatusCheckInterval elapses")]
        public event NodeCheckStatusEventHandler NodeStatusElapsed
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.StatusElapsed), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.StatusElapsed), value); }
        }

        [Category("Action"), Description("Raised when a node is repositioned")]
        public event NodeRepositionedEventHandler NodeRepositioned
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.Repositioned), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.Repositioned), value); }
        }

        [Category("Action"), Description("Raised when a node is double clicked")]
        public event NodeDoubleClickedEventHandler NodeDoubleClicked
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.DoubleClicked), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.DoubleClicked), value); }
        }

        [Category("Action"), Description("Raised when a node's detail button is clicked")]
        public event NodeDetailsClickedEventHandler NodeDetailsClicked
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.DetailsClicked), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.DetailsClicked), value); }
        }

        [Category("Action"), Description("Raised when a node is deleted")]
        public event NodeDeleteClickedEventHandler NodeDeleted
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.DeleteClicked), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.DeleteClicked), value); }
        }

        [Category("Action"), Description("Raised when the diagram is initialized -- after all the nodes have been added, and the offsets calculated")]
        public event DiagramInitializedEventHandler DiagramInitialized
        {
            add { Events.AddHandler(StringEnum.GetStringValue(ExecutingEvent.DiagramInitialized), value); }
            remove { Events.RemoveHandler(StringEnum.GetStringValue(ExecutingEvent.DiagramInitialized), value); }
        }

        public void RaiseNodeEvent(ExecutingEvent eventType, EventArgs e)
        {
            if (Events[StringEnum.GetStringValue(eventType)] != null)
            {
                switch (eventType)
                {
                    case ExecutingEvent.Repositioned:
                        //save changes to viewstate
                        DiagramContainer dContainer =
                            ReturnDiagramContainerByUniqueNodeIdentifier(((NodeRepositionEventArgs)e).NodeUniqueIdentifier);

                        int getIndex = dContainer.AllNodes.FindIndex(new Predicate<DiagramNode>(delegate(DiagramNode dn)
                        {
                            return dn.NodeUniqueIdentifier == ((NodeRepositionEventArgs)e).NodeUniqueIdentifier;
                        }));

                        dContainer.AllNodes[getIndex].XPos = ((NodeRepositionEventArgs)e).X;
                        dContainer.AllNodes[getIndex].YPos = ((NodeRepositionEventArgs)e).Y;

                        /*
                        InternalDiagramNode inode =
                            ReturnInternalNodeByUniqueIdentifier(((NodeRepositionEventArgs)e).NodeUniqueIdentifier);
                        
                        inode.XPos = ((NodeRepositionEventArgs)e).X;
                        inode.YPos = ((NodeRepositionEventArgs)e).Y;
                        */

                        //callback
                        ((NodeRepositionedEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.Repositioned)])(this, (NodeRepositionEventArgs)e);
                        break;
                    case ExecutingEvent.DetailsClicked:
                        ((NodeDetailsClickedEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.DetailsClicked)])(this, (NodeDetailsEventArgs)e);
                        break;
                    case ExecutingEvent.DoubleClicked:
                        ((NodeDoubleClickedEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.DoubleClicked)])(this, (NodeDetailsEventArgs)e);
                        break;
                    case ExecutingEvent.StatusElapsed:
                        ((NodeCheckStatusEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.StatusElapsed)])(this, (NodeStatusEventArgs)e);
                        break;
                    case ExecutingEvent.DeleteClicked:
                        ((NodeDeleteClickedEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.DeleteClicked)])(this, (NodeDetailsEventArgs)e);
                        break;
                    case ExecutingEvent.DiagramInitialized:
                        ((DiagramInitializedEventHandler)Events[StringEnum.GetStringValue(ExecutingEvent.DiagramInitialized)])(this, (DiagramInitializedEventArgs)e);
                        break;
                }
            }
        }

        internal string UniqueDiagramIdentifier
        {
            get
            {
                if (ViewState["_uniqueDiagramIdentifier"] == null)
                    ViewState["_uniqueDiagramIdentifier"] =
                        Guid.NewGuid().ToString().Replace("-", "").Trim().Substring(0, 10);

                return ViewState["_uniqueDiagramIdentifier"].ToString();
            }
        }

        public bool PreloadImages
        {
            get
            {
                if (ViewState["_preloadImages"] == null)
                    return true;
                return (bool)ViewState["_preloadImages"];
            }

            set { ViewState["_preloadImages"] = value; }
        }

        public string BaseUrl
        {
            get
            {
                if (ViewState["_baseUrl"] == null)
                    ViewState["_baseUrl"] = Utils.HomeUrl;

                //throw new Exception("You must set the BaseUrl property! Is it " + Utils.HomeUrl + "? Or do you have a subdirectory as well?");

                return ViewState["_baseUrl"].ToString();
            }
            set { ViewState["_baseUrl"] = value; }
        }

        internal int XOffSet
        {
            get
            {
                if (ViewState["_xOffset"] == null)
                    return 0;

                return (int)ViewState["_xOffset"];
            }

            private set
            {
                ViewState["_xOffset"] = value;
            }
        }

        internal int YOffSet
        {
            get
            {
                if (ViewState["_yOffset"] == null)
                    return 0;

                return (int)ViewState["_yOffset"];
            }

            private set
            {
                ViewState["_yOffset"] = value;
            }
        }

        public string GlobalLineColor
        {
            get
            {
                if (ViewState["_globalLineColor"] == null)
                    return "333333";
                return ViewState["_globalLineColor"].ToString();
            }
            set { ViewState["_globalLineColor"] = value; }
        }

        public int GlobalLinePixelWidth
        {
            get
            {
                if (ViewState["_globalLinePixelWidth"] == null)
                    return 1;
                return (int)ViewState["_globalLinePixelWidth"];
            }
            set { ViewState["_globalLinePixelWidth"] = value; }
        }

        public bool GlobalShowDetailsButton
        {
            get
            {
                if (ViewState["_globalShowDetailsButton"] == null)
                    return false;

                return (bool)ViewState["_globalShowDetailsButton"];
            }
            set
            {
                ViewState["_globalShowDetailsButton"] = value;
            }
        }

        public LineType GlobalLineType
        {
            get
            {
                if (ViewState["_globalLineType"] == null)
                    return LineType.Direct;
                return (LineType)ViewState["_globalLineType"];
            }
            set { ViewState["_globalLineType"] = value; }
        }

        public LineDecoration GlobalLineDecoration
        {
            get
            {
                if (ViewState["_globalLineDecoration"] == null)
                    return LineDecoration.Solid;

                return (LineDecoration)ViewState["_globalLineDecoration"];
            }
            set { ViewState["_globalLineDecoration"] = value; }
        }

        public virtual int NodeStatusCheckInterval
        {
            get { if (ViewState["_nodeStatusCheckInterval"] != null) { return (int)ViewState["_nodeStatusCheckInterval"]; } else { return -1; } }
            set { ViewState["_nodeStatusCheckInterval"] = value; }
        }

        public virtual int ZIndex
        {
            get { if (ViewState["_zIndex"] != null) { return (int)ViewState["_zIndex"]; } else { ViewState["_zIndex"] = 2000; return 2000; } }
            set { ViewState["_zIndex"] = value; }
        }

        public virtual CallBackType LastCallbackType
        {
            get
            {
                if (ViewState["_lastCallBackType"] == null)
                    return CallBackType.Undefined;
                else
                    return (CallBackType)ViewState["_lastCallBackType"];
            }
            set { ViewState["_lastCallBackType"] = value; }
        }

        public virtual bool AllowBodyDragging
        {
            get
            {
                if (ViewState["_allowBodyDragging"] == null)
                    return false;
                else
                    return (bool)ViewState["_allowBodyDragging"];
            }
            set { ViewState["_allowBodyDragging"] = value; }
        }

        public virtual string OnWarningCssClass
        {
            get
            {
                if (ViewState["_onWarningCssClass"] != null)
                    return ViewState["_onWarningCssClass"].ToString();
                else
                    return "";
            }
            set
            {
                ViewState["_onWarningCssClass"] = value;
            }
        }

        public virtual string OnErrorCssClass
        {
            get
            {
                if (ViewState["_onErrorCssClass"] != null)
                    return ViewState["_onErrorCssClass"].ToString();
                else
                    return "";
            }
            set
            {
                ViewState["_onErrorCssClass"] = value;
            }
        }

        public virtual string OnInfoCssClass
        {
            get
            {
                if (ViewState["_onInfoCssClass"] != null)
                    return ViewState["_onInfoCssClass"].ToString();
                else
                    return "";
            }
            set
            {
                ViewState["_onInfoCssClass"] = value;
            }
        }

        //using session to persist x,y coords when not saving to db
        public virtual List<DiagramNode> AllNodes
        {
            get
            {
                if (Page.Session["AllNodes_" + UniqueDiagramIdentifier] == null)
                    Page.Session["AllNodes_" + UniqueDiagramIdentifier] = new List<DiagramNode>();

                return (List<DiagramNode>)Page.Session["AllNodes_" + UniqueDiagramIdentifier];
            }
            set
            {
                Page.Session["AllNodes_" + UniqueDiagramIdentifier] = value;
            }
        }

        public DiagramNode ReturnDiagramNodeByNodeId(string id)
        {
            foreach (DiagramContainer dc in AllDiagramContainers)
                foreach (DiagramNode dn in dc.AllNodes)
                    if (dn.NodeID.Equals(id))
                        return dn;
            return null;
        }

        internal List<DiagramContainer> AllDiagramContainers
        {
            get
            {
                List<DiagramContainer> allContainers = new List<DiagramContainer>();
                List<Control> holdNodes = new List<Control>();
                Utils.RecursivelyFindAllTypesOfControl(this.Page, typeof(DiagramContainer), ref holdNodes);
                foreach (Control cl in holdNodes)
                    allContainers.Add((DiagramContainer)cl);

                return allContainers;
            }
        }

        internal DiagramContainer ReturnDiagramContainerByUniqueNodeIdentifier(int id)
        {
            foreach (DiagramContainer dc in AllDiagramContainers)
            {
                if (dc.AllNodes.Find(new Predicate<DiagramNode>(delegate(DiagramNode dn)
                {
                    return dn.NodeUniqueIdentifier == id;
                })) != null)
                {
                    return dc;
                }
            }
            return null;
        }

        public DiagramNode ReturnDiagramNodeIndexByUniqueIdentifier(int id)
        {
            foreach (DiagramContainer dc in AllDiagramContainers)
                foreach (DiagramNode dn in dc.AllNodes)
                    if (dn.NodeUniqueIdentifier.Equals(id))
                        return dn;
            return null;
        }

        internal StringBuilder allDragging = new StringBuilder();
        internal StringBuilder allChildImages = new StringBuilder();
        internal StringBuilder allParentImages = new StringBuilder();

        public DiagramContainer()
        {

        }

        private void CreateDiagrammingJavascript()
        {
            //create returnImageFunction -- dependency from the diagramming.js file
            StringBuilder returnImage = new StringBuilder();
            returnImage.Append("function returnTransparentPixel() { " + Environment.NewLine);
            returnImage.Append("rPix = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?transparent=true'; " + Environment.NewLine);
            returnImage.Append("return rPix;" + Environment.NewLine);
            returnImage.Append("}" + Environment.NewLine);

            returnImage.Append("function returnImage(nbr, dir, col, deco, wid) { " + Environment.NewLine);
            returnImage.Append("var rImage = '';" + Environment.NewLine);
            //returnImage.Append("window.status = nbr + ' , ' + dir; " + Environment.NewLine);
            returnImage.Append("rImage = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=' + col + '&dir=' + dir + '&box=' + nbr + '&deco=' + deco + '&wid=' + wid;");
            returnImage.Append("return rImage;" + Environment.NewLine);
            returnImage.Append("} " + Environment.NewLine);

            returnImage.Append("function returnArrow(nbr, dir, col, deco, wid, lType) { " + Environment.NewLine);
            returnImage.Append("var rImage = '';" + Environment.NewLine);
            //returnImage.Append("window.status = nbr + ' , ' + dir; " + Environment.NewLine);
            returnImage.Append("rImage = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=' + col + '&dir=' + dir + '&box=' + nbr + '&deco=' + deco + '&wid=' + wid + '&arrow=true'; ");
            returnImage.Append("return rImage;" + Environment.NewLine);
            returnImage.Append("} " + Environment.NewLine);

            returnImage.Append("function SetInitPositionForAllChildren(dependentIds) { ");
            returnImage.Append("var getDependencies = dependentIds.split(','); ");
            returnImage.Append("for (d = 0; d < getDependencies.length; d++) { ");
            returnImage.Append("var gDependency = document.getElementById(getDependencies[d]); ");
            returnImage.Append("if (gDependency) { ");
            returnImage.Append("var Bx = gDependency.style.left; ");
            returnImage.Append("var By = gDependency.style.top; ");
            returnImage.Append("Bx = parseInt(Bx.replace('px','')); By = parseInt(By.replace('px','')); ");
            returnImage.Append("document.getElementById(getDependencies[d] + 'InitPosition').innerHTML = Bx + ',' + By; ");

            returnImage.Append(Page.ClientScript.GetCallbackEventReference(this, "'" +
                                ((int)CallBackType.NodeBeingRepositioned).ToString()
                                + "' + Bx + '|' + By + '|' + getDependencies[d]", "nodeSuccessfullyRepositioned", "null") + "; ");

            returnImage.Append("} ");
            returnImage.Append("} ");
            returnImage.Append("} ");


            /*
            StringBuilder returnArrow = new StringBuilder();
            returnArrow.Append("function returnArrow(type) { " + Environment.NewLine);
            returnArrow.Append("var rArrow = '';" + Environment.NewLine);
            returnArrow.Append("switch (type) { " + Environment.NewLine);
            returnArrow.Append("case 'down': rArrow = '" + Page.ClientScript.GetWebResourceUrl(typeof(InternalDiagramNode), "Heckel.EasyTools.Diagramming.Resources.redArrowDown.gif") + "'; break; " + Environment.NewLine);
            returnArrow.Append("case 'up': rArrow = '" + Page.ClientScript.GetWebResourceUrl(typeof(InternalDiagramNode), "Heckel.EasyTools.Diagramming.Resources.redArrowUp.gif") + "'; break; " + Environment.NewLine);
            returnArrow.Append("}" + Environment.NewLine);
            returnArrow.Append("return rArrow;" + Environment.NewLine);
            returnArrow.Append("}" + Environment.NewLine);
             * */


            if (IsEnclosedInUpdatePanel)
            {
                ScriptManager.RegisterClientScriptInclude(this, this.GetType(), "diagramming",
                    Page.ClientScript.GetWebResourceUrl(typeof(InternalDiagramNode), "Heckel.EasyTools.Diagramming.Resources.diagramming.js"));

                ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "diagrammingImageBuilding", returnImage.ToString(), true);
            }
            else
            {
                if (!Page.ClientScript.IsClientScriptIncludeRegistered("diagramming"))
                    Page.ClientScript.RegisterClientScriptInclude("diagramming", Page.ClientScript.GetWebResourceUrl(typeof(InternalDiagramNode), "Heckel.EasyTools.Diagramming.Resources.diagramming.js"));

                if (!Page.ClientScript.IsClientScriptBlockRegistered("diagrammingImageBuilding"))
                    Page.ClientScript.RegisterClientScriptBlock(typeof(InternalDiagramNode), "diagrammingImageBuilding", returnImage.ToString(), true);
            }

            //if (!Page.ClientScript.IsClientScriptBlockRegistered("diagrammingArrowBuilding"))
            //    Page.ClientScript.RegisterClientScriptBlock(typeof(InternalDiagramNode), "diagrammingArrowBuilding", returnArrow.ToString(), true);
        }

        protected override void CreateChildControls()
        {
            //if (!Page.IsCallback)
            //{
            //load serialized nodes from viewstate
            List<LineDecoration> distinctLineDecorations = new List<LineDecoration>();
            List<string> distinctLineColors = new List<string>();
            List<int> distinctLineWidths = new List<int>();
            
            
            //Agragamos los Nodos para estar al tanto con Cuadernia
            if (Page.Session["diagrama"]!= null)
                this.AllNodes = ((DiagramContainer)Page.Session["diagrama"]).AllNodes;



            foreach (DiagramNode node in AllNodes)
            {
                InternalDiagramNode nNode = new InternalDiagramNode(node.ImageUrl, node.NodeText,
                    node.NodeDescription, node.NodeID, node.NodeUniqueIdentifier, node.XPos, node.YPos,
                    node.ParentOfIds, node.ChildOfIds);

                nNode.Width = node.Width;
                nNode.Height = node.Height;
                nNode.BackColor = node.BackColor;
                nNode.ForeColor = node.ForeColor;
                nNode.BorderColor = node.BorderColor;

                nNode.LockChildrenToXPlaneOnDrag = node.LockChildrenToXPlaneOnDrag;
                nNode.LockChildrenToYPlaneOnDrag = node.LockChildrenToYPlaneOnDrag;
                nNode.AutoSnapChildrenBelow = node.AutoSnapChildrenBelow;
                nNode.DraggingEnabled = node.DraggingEnabled;
                nNode.DrawParentLines = node.DrawParentLines;
                nNode.DrawChildLines = node.DrawChildLines;

                nNode.TextPlacement = node.TextPlacement;

                nNode.NodeLineColor = node.NodeLineColor;
                nNode.NodeLinePixelWidth = node.NodeLinePixelWidth;
                nNode.NodeLineType = node.NodeLineType;
                nNode.NodeLineDecoration = node.NodeLineDecoration;

                //DiagramNode nNode = new DiagramNode(node.NodeImageUrl, node.NodeText, node.NodeDescription, node.NodeID, node.NodeUniqueIdentifier, node.XPos, node.YPos, node.ParentOfIds, node.ChildOfIds);
                this.Controls.Add(nNode);

                if (!distinctLineDecorations.Contains(nNode.NodeLineDecoration))
                    distinctLineDecorations.Add(nNode.NodeLineDecoration);

                if (!distinctLineColors.Contains(nNode.NodeLineColor))
                    distinctLineColors.Add(nNode.NodeLineColor);

                if (!distinctLineWidths.Contains(nNode.NodeLinePixelWidth))
                    distinctLineWidths.Add(nNode.NodeLinePixelWidth);
            }

            //list images to preload
            LiteralControl lc = new LiteralControl();
            StringBuilder imagesToLoad = new StringBuilder();
            imagesToLoad.Append("<div id=\"preload\" style=\"height:0;overflow:hidden\">");

            if (PreloadImages && GlobalLineType == LineType.Direct)
            {
                for (int i = 1; i < 200; i++)
                {
                    if (i % 10 == 0 || i < 10)
                    //if (i == 1 || i == 4 || i == 8 || i == 16 || i == 32 || i == 64 || i == 128 || i == 256)
                    {
                        foreach (string cx in distinctLineColors)
                        {
                            foreach (LineDecoration ld in distinctLineDecorations)
                            {
                                foreach (int w in distinctLineWidths)
                                {
                                    imagesToLoad.Append("<img alt = '' src = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=" + cx + "&dir=up&box=" + i.ToString() + "&deco=" + ((int)ld).ToString() + "&wid=" + w.ToString() + "'/>");
                                    imagesToLoad.Append("<img alt = '' src = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=" + cx + "&dir=down&box=" + i.ToString() + "&deco=" + ((int)ld).ToString() + "&wid=" + w.ToString() + "'/>");
                                    imagesToLoad.Append("<img alt = '' src = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=" + cx + "&dir=up&box=" + i.ToString() + "&deco=" + ((int)ld).ToString() + "&wid=" + w.ToString() + "'/>");
                                    imagesToLoad.Append("<img alt = '' src = '" + BaseUrl + "/Heckel.EasyTools.Diagramming.ashx?col=" + cx + "&dir=down&box=" + i.ToString() + "&deco=" + ((int)ld).ToString() + "&wid=" + w.ToString() + "'/>");
                                }
                            }
                        }

                        //imagesToLoad.Append("<img alt = '' src = '" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.draw" + i.ToString() + "up.gif") + "'/>");
                        //imagesToLoad.Append("<img alt = '' src = '" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.draw" + i.ToString() + "down.gif") + "'/>");
                    }
                }
            }

            //imagesToLoad.Append("<img alt = '' src = '" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.redArrowUp.gif") + "'/>");
            //imagesToLoad.Append("<img alt = '' src = '" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.redArrowDown.gif") + "'/>");

            imagesToLoad.Append("</div>");
            Controls.Add(new LiteralControl(imagesToLoad.ToString()));

            //modal css
            string modalCss = "<link rel=\"stylesheet\" href=\"" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.modalbox.css") + "\" type=\"text/css\" media=\"screen\" />";
            Controls.Add(new LiteralControl(modalCss));

            //dynamic css class needed for modal
            StringBuilder modalLoading = new StringBuilder();
            modalLoading.Append("<style type=\"text/css\"> #MB_loading { padding: 1.5em; text-indent: -10000px; background: transparent url(" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.spinner.gif") + ") 50% 0 no-repeat;</style>");
            Controls.Add(new LiteralControl(modalLoading.ToString()));

            //tooltip css
            string tooltipCss = "<link rel=\"stylesheet\" href=\"" + Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.tooltips.css") + "\" type=\"text/css\" media=\"screen\" />";
            Controls.Add(new LiteralControl(tooltipCss));
            //}
        }

        /*
        public virtual DiagramNode FindNodeByClientId(string id)
        {
            foreach (Control dn in this.Controls)
                if (dn is DiagramNode)
                    if (((DiagramNode)dn).NodeID.Equals(id))
                        return (DiagramNode)dn;

            return null;
        }
         * */

        protected override void Render(HtmlTextWriter writer)
        {
            //if (!Page.IsCallback)
            //{
            string loader =
                    Page.ClientScript.GetCallbackEventReference(this, "'" +
                    ((int)CallBackType.DiagramInitialized).ToString() +
                    "' + setOffsets('" + UniqueDiagramIdentifier + "', " +
                    this.Width.Value.ToString() + "," + this.Height.Value.ToString() + ")",
                    "InitializeDiagram", "null") + "; ";

            //write holders -- will be given value once the callback is made 
            writer.Write("<input type='hidden' id='" + UniqueDiagramIdentifier + "_xStart'/>");
            writer.Write("<input type='hidden' id='" + UniqueDiagramIdentifier + "_xOffSet'/>");
            writer.Write("<input type='hidden' id='" + UniqueDiagramIdentifier + "_yStart'/>");
            writer.Write("<input type='hidden' id='" + UniqueDiagramIdentifier + "_yOffSet'/>");

            //string a = "alert('xstart:' + document.getElementById('" + UniqueDiagramIdentifier + "_xStart').value); ";
            if (IsEnclosedInUpdatePanel)
                ScriptManager.RegisterStartupScript(this, this.GetType(), "holdInit_" + UniqueDiagramIdentifier, loader, true);
            else
                Page.ClientScript.RegisterStartupScript(this.GetType(), "holdInit_" + UniqueDiagramIdentifier, loader, true);

            //registering child draggable scripts
            allDragging.Insert(0, "function initDragging_" + UniqueDiagramIdentifier + "() { ");
            allDragging.Append(" } ");

            if (!Page.IsPostBack)
                writer.Write("<script type=\"text/javascript\">" + allDragging.ToString() + "</script>");
            else
            {
                if (IsEnclosedInUpdatePanel)
                    ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "allDragging", allDragging.ToString(), true);
                else
                    Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "allDragging", allDragging.ToString(), true);
            }

            if (IsEnclosedInUpdatePanel)
                ScriptManager.RegisterStartupScript(this, this.GetType(), "initDragScript_" + UniqueDiagramIdentifier, " setTimeout(\"initDragging_" + UniqueDiagramIdentifier + "();\", 1000); ", true);
            else
                Page.ClientScript.RegisterStartupScript(this.GetType(), "initDragScript_" + UniqueDiagramIdentifier, " setTimeout(\"initDragging_" + UniqueDiagramIdentifier + "();\", 1000); ", true);

            //need to put down one relative div to see what kind of offsets we're looking at
            writer.Write("<style type=\"text/css\">.easydiagram_abs { position:absolute; }</style>");

            writer.Write("<div id='" + UniqueDiagramIdentifier + "' style='width:" + this.Width.Value.ToString() + "px;height:" + this.Height.Value.ToString() + "px;position:relative;'>");
            //writer.Write("<div id='" + UniqueDiagramIdentifier + "' style='visibility:hidden;width:1px;height:1px;position:relative;'>");

            //write out dragging images
            writer.Write(allParentImages);
            writer.Write(allChildImages);

            //write out all nodes
            List<Control> aNodes = new List<Control>();
            Utils.RecursivelyFindAllTypesOfControl(this, typeof(InternalDiagramNode), ref aNodes);
            foreach (Control d in aNodes)
                writer.Write(((InternalDiagramNode)d).ToString());

            writer.Write("</div>");
            //}
            base.Render(writer);
        }

        protected override void OnPreRender(EventArgs e)
        {
            //if (!Page.IsCallback)
            //{
            //initial script (for drawing initial lines and initializing timer if needed);
            StringBuilder bodyDragging = new StringBuilder();
            StringBuilder loadFunction = new StringBuilder();

            //if (!Page.ClientScript.IsStartupScriptRegistered("initLoadScript_" + UniqueDiagramIdentifier))
            //{
            //previous was in the init tag
            CreateDiagrammingJavascript();

            //preload the images
            StringBuilder preLoader = new StringBuilder();
            preLoader.Append("preloadedImages = document.getElementById('preload').getElementsByTagName('img'); ");

            if (IsEnclosedInUpdatePanel)
            {
                ScriptManager.RegisterStartupScript(this, typeof(DiagramContainer), "preloadingImages", preLoader.ToString(), true);
                ScriptManager.RegisterClientScriptBlock(this, typeof(DiagramContainer), "globalPreloadedImages", "var preloadedImages;", true);
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "dragdrop", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.dom-drag.js"));
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "callbackevents", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.callbackevents.js"));

                //modal dialogue functionality
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "prototype", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.prototype.js"));
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "scriptaculous", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.scriptaculous.js?load=builder,effects"));
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "effects", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.effects.js"));
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "builder", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.builder.js"));
                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "modalbox", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.modalbox.js"));

                ScriptManager.RegisterClientScriptInclude(this, typeof(DiagramContainer), "tooltips", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.tooltips.js"));

            }
            else
            {
                Page.ClientScript.RegisterStartupScript(typeof(DiagramContainer), "preloadingImages", preLoader.ToString(), true);
                Page.ClientScript.RegisterClientScriptBlock(typeof(DiagramContainer), "globalPreloadedImages", "var preloadedImages;", true);
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "dragdrop", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.dom-drag.js"));
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "callbackevents", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.callbackevents.js"));

                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "prototype", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.prototype.js"));
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "scriptaculous", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.scriptaculous.js?load=builder,effects"));
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "effects", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.effects.js"));
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "builder", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.builder.js"));
                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "modalbox", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.modalbox.js"));

                Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "tooltips", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.tooltips.js"));
            }

            //tooltips functionality

            //css functionality
            //Page.ClientScript.RegisterClientScriptInclude(typeof(DiagramContainer), "cssmanipulation", Page.ClientScript.GetWebResourceUrl(typeof(DiagramContainer), "Heckel.EasyTools.Diagramming.Resources.cssmanipulation.js"));

            if (AllowBodyDragging)
            {
                bodyDragging.Append("var isBodyDragging = false; " +
                                    "var initX = 0; " +
                                    "var initY = 0; " +
                                    "var dragX = 0; " +
                                    "var dragY = 0; " +
                                    "var bDrag = 0; " + Environment.NewLine);

                bodyDragging.Append("document.onmousedown = function(e) " +
                                    "{ " +
                                    "    isBodyDragging = true; " +
                                    "    if (!e) var e = window.event; " +
                                    "    if (e.pageX || e.pageY) " +
                                    "    { " +
                                    "        initX = e.pageX; " +
                                    "        initY = e.pageY; " +
                                    "    } " +
                                    "    else if (e.clientX || e.clientY) " +
                                    "    { " +
                                    "        initX = e.clientX; " +
                                    "        initY = e.clientY; " +
                                    "    } " +
                                    "    //window.status = 'set init: ' + initX + ',' + initY; return true;" +
                                    "} " + Environment.NewLine);


                bodyDragging.Append("document.onmouseup = function(e) { isBodyDragging = false; " + Environment.NewLine);

                bodyDragging.Append("document.onmousemove = function(e) " +
                                     "{ " +
                                     "if (isBodyDragging) " +
                                     "{ " +
                                     "bDrag++; " +
                                     "if (bDrag % 5 == 0) { " +
                                     "if (!e) var e = window.event; " +
                                     "if (e.pageX || e.pageY) " +
                                     " { " +
                                     "  dragX = e.pageX; " +
                                     "  dragY = e.pageY; " +
                                     "} " +
                                     "else if (e.clientX || e.clientY) " +
                                     "{ " +
                                     "  dragX = e.clientX; " +
                                     "  dragY = e.clientY; " +
                                     "} " +
                                     " //window.status = \"x: \" + (dragX - initX) + \", y:\" + (dragY - initY); ");
            }

            StringBuilder holdCoordinates = new StringBuilder();

            //foreach(DiagramNode dn in AllNodes)
            //{
            foreach (Control dn in this.Controls)
            {
                if (dn is InternalDiagramNode)
                {
                    InternalDiagramNode dnx = (InternalDiagramNode)dn;
                    string _parentOfIds = "";
                    foreach (string dependentNode in dnx.ParentOfIds)
                        _parentOfIds += dependentNode + " ";
                    _parentOfIds = _parentOfIds.Trim().Replace(" ", ",");

                    string _childOfIds = "";
                    foreach (string dependentNode in dnx.ChildOfIds)
                        _childOfIds += dependentNode + " ";
                    _childOfIds = _childOfIds.Trim().Replace(" ", ",");

                    loadFunction.Append("if (document.getElementById('" + dnx.NodeID + "')) { ");

                    bool isSnapped = false;
                    foreach (string cidx in dnx.ChildOfIds)
                    {
                        DiagramNode getParentNode =
                            AllNodes.Find(
                            new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == cidx; }));

                        if (getParentNode.AutoSnapChildrenBelow)
                        {
                            isSnapped = true;
                            break;
                        }
                    }

                    if (!isSnapped)
                    {
                        if (dnx.DrawParentLines)
                            loadFunction.Append("drawParentLine('" + dnx.NodeID + "','" + _parentOfIds + "', " + dnx.XPos + "," + dnx.YPos + "); ");

                        if (dnx.DrawChildLines)
                            loadFunction.Append("drawChildLine('" + dnx.NodeID + "', '" + _childOfIds + "', " + dnx.XPos + "," + dnx.YPos + "); ");
                    }


                    if (dnx.LockChildrenToXPlaneOnDrag || dnx.LockChildrenToYPlaneOnDrag)
                    {
                        Dictionary<string, List<string>> getAllParents = new Dictionary<string, List<string>>();
                        Dictionary<string, List<string>> getAllChildren = new Dictionary<string, List<string>>();
                        foreach (string pid in dnx.ParentOfIds)
                        {
                            DiagramNode pnode =
                                AllNodes.Find(
                                new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == pid; }));

                            getAllParents.Add(pid, new List<string>());
                            getAllChildren.Add(pid, new List<string>());

                            foreach (string pidx in pnode.ParentOfIds)
                            {
                                //DiagramNode getChildNode =
                                //    AllNodes.Find(new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == cidx; }));

                                if (!pnode.AutoSnapChildrenBelow)
                                    getAllParents[pid].Add(pidx);
                            }

                            foreach (string cidx in pnode.ChildOfIds)
                            {
                                DiagramNode getParentNode =
                                    AllNodes.Find(
                                    new Predicate<DiagramNode>(delegate(DiagramNode dx) { return dx.NodeID == cidx; }));

                                if (!getParentNode.AutoSnapChildrenBelow)
                                    getAllChildren[pid].Add(cidx);


                                //if (getParentNode.AutoSnapChildrenBelow &&
                                //    !IsChildSnappedBelowParent(pnode, getParentNode))
                                //    getAllChildren[pid].Add(cidx);
                            }
                        }

                        StringBuilder allParents = new StringBuilder();
                        foreach (KeyValuePair<string, List<string>> allParentDeps in getAllParents)
                        {
                            if (allParentDeps.Value.Count > 0)
                            {
                                allParents.Append(allParentDeps.Key + ":");
                                foreach (string apx in allParentDeps.Value)
                                    allParents.Append(apx + ",");
                                allParents.Append("~");
                            }
                        }

                        string getallparents = "";
                        if (allParents.Length > 0)
                            getallparents = allParents.ToString().Trim();

                        StringBuilder allChildren = new StringBuilder();
                        foreach (KeyValuePair<string, List<string>> allChildDeps in getAllChildren)
                        {
                            if (allChildDeps.Value.Count > 0)
                            {
                                allChildren.Append(allChildDeps.Key + ":");
                                foreach (string apx in allChildDeps.Value)
                                    allChildren.Append(apx + ",");
                                allChildren.Append("~");
                            }
                        }

                        string getallchildren = "";
                        if (allChildren.Length > 0)
                            getallchildren = allChildren.ToString().Trim();

                        loadFunction.Append("drawLockedNodes('" + dnx.NodeID + "','" + _parentOfIds + "', " + dnx.XPos.ToString() + ", " + dnx.YPos.ToString() + ", " +
                            dnx.LockChildrenToXPlaneOnDrag.ToString().ToLower() + ", " +
                            dnx.LockChildrenToYPlaneOnDrag.ToString().ToLower() + ", " +
                            dnx.AutoSnapChildrenBelow.ToString().ToLower() + ", '" +
                            getallparents + "','" + getallchildren + "'); ");
                    }

                    loadFunction.Append(" } ");

                    //holdCoordinates.Append("'@" + ((InternalDiagramNode)dn).NodeID + "," + ((InternalDiagramNode)dn).NodeUniqueIdentifier
                    //     + ",' + Element.viewportOffset('" + ((InternalDiagramNode)dn).NodeID + 
                    //     "').left + ',' + Element.viewportOffset('" + ((InternalDiagramNode)dn).NodeID + "').top" + " + ");

                    if (AllowBodyDragging)
                    {
                        bodyDragging.Append("MoveNode('" + dnx.NodeID + "', '" + _parentOfIds + "','" + _childOfIds + "', (dragX - initX), (dragY - initY)); " + Environment.NewLine);
                        bodyDragging.Append("drawParentLine('" + dnx.NodeID + "','" + _parentOfIds + "', " + dnx.XPos + "," + dnx.YPos + "); drawChildLine('" + dnx.NodeID + "', '" + _childOfIds + "', " + dnx.XPos + "," + dnx.YPos + "); " + Environment.NewLine);
                    }
                }

                //}

                if (NodeStatusCheckInterval != -1)
                {
                    //loadFunction.Append("setInterval(\"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.CheckingNodeStatuses).ToString() + "|' + " + holdCoordinates.ToString(), "ReturnNodeStatuses", "null") + "\", " + NodeStatusCheckInterval + "); ");
                    loadFunction.Append("setInterval(\"" + Page.ClientScript.GetCallbackEventReference(this, "'" + ((int)CallBackType.CheckingNodeStatuses).ToString() + "'", "ReturnNodeStatuses", "null") + "\", " + NodeStatusCheckInterval + "); ");
                }

                if (AllowBodyDragging)
                {
                    bodyDragging.Append("} } " +
                                        "return true; " +
                                        "} " + Environment.NewLine);

                    if (IsEnclosedInUpdatePanel)
                        ScriptManager.RegisterClientScriptBlock(this, typeof(DiagramContainer), "initDragScript_" + UniqueDiagramIdentifier, bodyDragging.ToString(), true);
                    else
                        Page.ClientScript.RegisterClientScriptBlock(typeof(DiagramContainer), "initDragScript_" + UniqueDiagramIdentifier, bodyDragging.ToString(), true);
                }
            }

            //return css class name
            StringBuilder returnClassName = new StringBuilder();
            returnClassName.Append("function returnClassName(logType) { ");
            returnClassName.Append("switch(logType) { ");
            returnClassName.Append("case 'warning': ");
            returnClassName.Append("return '" + OnWarningCssClass + "'; ");
            returnClassName.Append("case 'info': ");
            returnClassName.Append("return '" + OnInfoCssClass + "'; ");
            returnClassName.Append("case 'error': ");
            returnClassName.Append("return '" + OnErrorCssClass + "'; ");
            returnClassName.Append("} ");
            returnClassName.Append("} ");

            if (IsEnclosedInUpdatePanel)
            {
                ScriptManager.RegisterClientScriptBlock(this, typeof(DiagramContainer), "returnClassName", returnClassName.ToString(), true);
                ScriptManager.RegisterStartupScript(this, typeof(DiagramContainer), "initLoadScript_" + UniqueDiagramIdentifier, loadFunction.ToString(), true);
            }
            else
            {
                Page.ClientScript.RegisterClientScriptBlock(typeof(DiagramContainer), "returnClassName", returnClassName.ToString(), true);
                Page.ClientScript.RegisterStartupScript(typeof(DiagramContainer), "initLoadScript_" + UniqueDiagramIdentifier, loadFunction.ToString(), true);
            }
            //}
            base.OnPreRender(e);
        }

        internal bool IsChildSnappedBelowParent(DiagramNode child, DiagramNode parent)
        {
            return child.XPos == parent.XPos;
            /*

            if ((child.XPos == parent.XPos - 10 || child.XPos <= parent.XPos + 10) &&
                (child.YPos >= parent.YPos - 10 || child.YPos <= parent.YPos + 10))
                return true;

            return false;
            */
        }

        public void RaiseCallbackEvent(String eventArgument)
        {
            string callbackString = eventArgument.Substring(1, eventArgument.Length - 1);
            switch (Convert.ToInt32(eventArgument.Substring(0, 1)))
            {
                case (int)CallBackType.NodeBeingRepositioned:
                    LastCallbackType = CallBackType.NodeBeingRepositioned;
                    string[] splitter = callbackString.Split('|');

                    DiagramNode getNode = ReturnDiagramNodeByNodeId(splitter[2]);
                    if (getNode != null)
                    {
                        RaiseNodeEvent(ExecutingEvent.Repositioned,
                            new NodeRepositionEventArgs(getNode.NodeText, getNode.NodeUniqueIdentifier,
                                Int32.Parse(splitter[0]), Int32.Parse(splitter[1])));
                    }

                    break;
                case (int)CallBackType.CheckingNodeStatuses:
                    LastCallbackType = CallBackType.CheckingNodeStatuses;

                    //for future ref, maybe the current x and y nodes would be gotten from here:
                    //string[] getNodeStatusDetails = callbackString.Split('@');

                    Dictionary<string, NodeStatus> allNodesStatusObjects = new Dictionary<string, NodeStatus>();
                    foreach (Control dn in this.Controls)
                    {
                        if (dn is InternalDiagramNode)
                        {
                            InternalDiagramNode idn = (InternalDiagramNode)dn;
                            allNodesStatusObjects.Add(idn.NodeID, new NodeStatus(idn.NodeID,
                                                idn.NodeUniqueIdentifier.ToString(), idn.XPos, idn.YPos));
                        }
                    }
                    /*
                    foreach (string c in getNodeStatusDetails)
                    {
                        if (c != "")
                        {
                            string[] splitCVals = c.Split(',');
                            //0 = node id; 1 = node unique id; 2 = x; 3 = y
                            allNodesStatusObjects.Add(splitCVals[0], new NodeStatus(splitCVals[0], splitCVals[1], 
                                Int32.Parse(splitCVals[2]), Int32.Parse(splitCVals[3])));
                        }
                    }
                     * */

                    checkNodeStatus = new NodeStatusEventArgs(allNodesStatusObjects);
                    RaiseNodeEvent(ExecutingEvent.StatusElapsed, checkNodeStatus);
                    break;
                case (int)CallBackType.DiagramInitialized:
                    LastCallbackType = CallBackType.DiagramInitialized;
                    string[] getCoordinates = callbackString.Split('~');

                    XOffSet = Int32.Parse(getCoordinates[0]);
                    YOffSet = Int32.Parse(getCoordinates[1]);

                    DiagramInitializedEventArgs e =
                        new DiagramInitializedEventArgs(XOffSet, YOffSet);

                    RaiseNodeEvent(ExecutingEvent.DiagramInitialized, e);
                    break;
            }
        }

        public string GetCallbackResult()
        {
            switch (LastCallbackType)
            {
                case CallBackType.CheckingNodeStatuses:

                    StringBuilder clientScript = new StringBuilder();
                    StringBuilder allNodes = new StringBuilder();

                    foreach (KeyValuePair<string, NodeStatus> ns in checkNodeStatus.AllStatuses)
                    {
                        allNodes.Append(ns.Key + "|");

                        if (ns.Value.HasErrors)
                            foreach (string allErrors in ns.Value.Errors)
                                clientScript.Append(ns.Key + "~e~|" + allErrors.ToString() + "@");

                        if (ns.Value.HasWarnings)
                            foreach (string allWarnings in ns.Value.Warnings)
                                clientScript.Append(ns.Key + "~w~|" + allWarnings.ToString() + "@");

                        if (ns.Value.HasInfo)
                            foreach (string allInfo in ns.Value.Info)
                                clientScript.Append(ns.Key + "~i~|" + allInfo.ToString() + "@");

                        /*
                        if (ns.HasMoveInstructions)
                        {
                            clientScript.Append(allMoveInstructions.Key.ToString() + "~m~|");
                            foreach (NodeStatus nodeInstructions in allMoveInstructions.Value)
                            {
                                clientScript += nodeInstructions.XPosDestination.ToString() + "," +
                                    nodeInstructions.YPosDestination.ToString() + "," + nodeInstructions.SpeedOfMove.ToString() + "@";
                            }
                        }
                         * */
                    }

                    string sScript = "";
                    if (clientScript.ToString() != "")
                        sScript = clientScript.ToString().Substring(0, clientScript.ToString().Length - 1);

                    LastCallbackType = CallBackType.Undefined;
                    return allNodes.ToString().Substring(0, allNodes.ToString().Length - 1) + "##" + sScript;
                case CallBackType.DiagramInitialized:
                    LastCallbackType = CallBackType.Undefined;
                    return "";
                default:
                    return "";
            }
        }
    }
}
